<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>

<!--
  tests for templates with invalid syntax
-->

<window title="XUL Invalid Template Tests" width="500" height="600"
        onload="runTest();"
        xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <script type="application/javascript"
          src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>

  <body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;"/>

<script>
<![CDATA[
SimpleTest.waitForExplicitFinish();

var consoleService = Components.classes["@mozilla.org/consoleservice;1"].
                       getService(Components.interfaces.nsIConsoleService);

function checkConsole(expectedError)
{
  var message = consoleService.getMessageArray()[0].message;
  is(message, expectedError, "logged message " + expectedError);
}

// each test consists of a pre function executed before the template build, an
// expected error message, and a post function executed after the template build
var tests = [

// <queryset> used in invalid location
{
  pre: template => template.insertBefore(document.createElement("queryset"), template.lastChild),
  error: "Error parsing template: unexpected <queryset> element",
  post: queryset => queryset.parentNode.removeChild(queryset)
},

// no member variable found
{
  pre: template => $("action").firstChild.removeAttribute("uri"),
  error: "Error parsing template: no member variable found. Action body should have an element with uri attribute",
  post: () => $("action").firstChild.setAttribute("uri", "?child")
},

// bad binding subject
{
  pre: template => $("binding").removeAttribute("subject"),
  error: "Error parsing template: <binding> requires a variable for its subject attribute",
  post: () => $("binding").setAttribute("subject", "?child"),
},

// bad binding predicate
{
  pre: template => $("binding").removeAttribute("predicate"),
  error: "Error parsing template: <binding> element is missing a predicate attribute",
  post: () => $("binding").setAttribute("predicate", "http://www.some-fictitious-zoo.com/rdf#name"),
},

// bad binding object
{
  pre: template => $("binding").setAttribute("object", "blah"),
  error: "Error parsing template: <binding> requires a variable for its object attribute",
  post: () => $("binding").setAttribute("object", "?name"),
},

// where condition missing a subject
{
  pre: function(template) { var rule = $("rule");
                            var where = document.createElement("where");
                            where.setAttribute("subject", "");
                            where.setAttribute("rel", "equals");
                            where.setAttribute("value", "Raven");
                            rule.appendChild(where);
                            return where; },
  error: "Error parsing template: <where> element is missing a subject attribute",
  post: function(where) { where.parentNode.removeChild(where); }
},

// where condition missing a rel
{
  pre: function(template) { var rule = $("rule");
                            var where = document.createElement("where");
                            where.setAttribute("subject", "?name");
                            where.setAttribute("rel", "");
                            where.setAttribute("value", "Raven");
                            rule.appendChild(where);
                            return where; },
  error: "Error parsing template: <where> element is missing a rel attribute",
  post: function(where) { where.parentNode.removeChild(where); }
},

// where condition missing a value
{
  pre: function(template) { var rule = $("rule");
                            var where = document.createElement("where");
                            where.setAttribute("subject", "?name");
                            where.setAttribute("rel", "equals");
                            where.setAttribute("value", "");
                            rule.appendChild(where);
                            return where; },
  error: "Error parsing template: <where> element is missing a value attribute",
  post: function(where) { where.parentNode.removeChild(where); }
},

// where condition missing a variable
{
  pre: function(template) { var rule = $("rule");
                            var where = document.createElement("where");
                            where.setAttribute("subject", "name");
                            where.setAttribute("rel", "equals");
                            where.setAttribute("value", "Raven");
                            rule.appendChild(where);
                            return where; },
  error: "Error parsing template: <where> element must have at least one variable as a subject or value",
  post: function(where) { where.parentNode.removeChild(where); }
},

// bad member container
{
  pre: template => $("member").setAttribute("container", "blah"),
  error: "Error parsing template: <member> requires a variable for its container attribute",
  post: () => $("member").setAttribute("container", "?uri"),
},

// bad member child
{
  pre: template => $("member").setAttribute("child", "blah"),
  error: "Error parsing template: <member> requires a variable for its child attribute",
  post: () => $("member").setAttribute("child", "?child"),
},

// bad triple subject
{
  pre: template => $("triple").removeAttribute("subject"),
  error: "Error parsing template: <triple> requires a variable for its subject attribute",
  post: () => $("triple").setAttribute("subject", "?child"),
},

// missing triple predicate
{
  pre: template => $("triple").removeAttribute("predicate"),
  error: "Error parsing template: <triple> should have a non-variable value as a predicate",
  post: () => $("triple").setAttribute("predicate", "http://www.some-fictitious-zoo.com/rdf#name"),
},

// bad triple predicate
{
  pre: template => $("triple").setAttribute("predicate", "?predicate"),
  error: "Error parsing template: <triple> should have a non-variable value as a predicate",
  post: () => $("triple").setAttribute("predicate", "http://www.some-fictitious-zoo.com/rdf#name"),
},

// bad triple object
{
  pre: template => $("triple").removeAttribute("object"),
  error: "Error parsing template: <triple> requires a variable for its object attribute",
  post: () => $("triple").setAttribute("object", "?name"),
},

// content not first element in query
{
  pre: function(template) { var content = $("content"); content.parentNode.appendChild(content); return content; },
  error: "Error parsing template: expected <content> to be first",
  post: content => content.parentNode.insertBefore(content, content.parentNode.firstChild),
},

// member container variable not bound
{
  pre: template => $("member").removeAttribute("container"),
  error: "Error parsing template: neither container or child variables of <member> has a value",
  post: () => $("member").setAttribute("container", "?uri"),
},

// neither triple subject or object variable are bound
{
  pre: template => $("triple").setAttribute("subject", "?blah"),
  error: "Error parsing template: neither subject or object variables of <triple> has a value",
  post: () => $("triple").setAttribute("subject", "?child"),
},

// neither triple subject or object variable are bound
{
  pre: function(template) { var triple = $("triple"); triple.setAttribute("subject", "blah");
                            triple.setAttribute("object", "blah"); },
  error: "Error parsing template: <triple> should have at least one variable as a subject or object",
  post: function() { var triple = $("triple"); triple.setAttribute("subject", "?uri");
                     triple.setAttribute("object", "?uri") }
},

// could not parse xml query expression
{
  firstXMLTest: true,
  pre: function(template) { $("query").setAttribute("expr", "something()"); },
  error: "Error parsing template: XPath expression in query could not be parsed",
  post: function() { }
},

// could not parse xml assign expression
{
  pre: function(template) { var query = $("query");
                            query.setAttribute("expr", "*");
                            var assign = document.createElement("assign");
                            assign.setAttribute("var", "?name");
                            assign.setAttribute("expr", "something()");
                            query.appendChild(assign);
                            return assign; },
  error: "Error parsing template: XPath expression in <assign> could not be parsed",
  post: function(assign) { assign.parentNode.removeChild(assign); }
},

// could not parse xml binding expression
{
  pre: function(template) { $("binding").setAttribute("predicate", "something()"); },
  error: "Error parsing template: XPath expression in <binding> could not be parsed",
  post: function() { $("binding").setAttribute("predicate", "[name]"); },
},

];

function runTest()
{
  var root = $("root");
  var template = $("template");
  while (test = tests.shift()) {
    consoleService.reset();
    var context = test.pre(template);
    root.builder.rebuild();
    checkConsole(test.error);
    test.post(context);

    // preload and set up for the xml datasource query error tests
    if (tests.length && tests[0].firstXMLTest) {
      var src = window.location.href.replace(/test_tmpl.*xul/, "animals.xml");
      xmlDoc = new XMLHttpRequest();
      xmlDoc.open("get", src, false);
      xmlDoc.send(null);

      var root = $("root");
      root.setAttribute("querytype", "xml");
      root.setAttribute("datasources", "animals.xml");
      $("binding").setAttribute("predicate", "[name]");

      function waitForDatasource() {
        // wait for the datasource to be available before continuing the test
        if (root.builder.datasource instanceof XMLDocument)
          runTest();
        else
          setTimeout(waitForDatasource, 100);
      }

      setTimeout(waitForDatasource, 0);
      return;
    }
  }
  SimpleTest.finish();
}

]]>
</script>

<vbox id="root" datasources="animals.rdf" ref="http://www.some-fictitious-zoo.com/birds">
<template id="template">
  <query id="query">
    <content id="content" uri="?uri"/>
    <member id="member" container="?uri" child="?child"/>
    <triple id="triple" subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/>
  </query>
  <rule id="rule">
    <binding id="binding" subject="?child" predicate="http://www.some-fictitious-zoo.com/rdf#name" object="?name"/>
    <action id="action">
      <label uri="?child" value="?name"/>
    </action>
  </rule>
</template>
</vbox>

</window>
